/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.scalia.meteocal.gui;

import com.scalia.meteocal.control.EventManager;
import com.scalia.meteocal.control.ForecastManager;
import com.scalia.meteocal.control.InvitationManager;
import com.scalia.meteocal.control.PlaceManager;
import com.scalia.meteocal.control.UserManager;
import com.scalia.meteocal.entity.Event;
import com.scalia.meteocal.entity.WeatherType;
import com.scalia.meteocal.weather.WeatherForecast;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.ejb.EJB;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.validator.ValidatorException;
import org.primefaces.component.spinner.Spinner;

/**
 *
 * @author gabriele
 */
@ManagedBean
@ViewScoped
public class CreateEventBean implements Serializable {

    @EJB
    PlaceManager placeManager;
    
    @EJB
    UserManager userManager;
    
    @EJB
    EventManager eventManager;
    
    @EJB
    InvitationManager invitationManager;
    
    @EJB
    ForecastManager forecastManager;

    private Event event;
    private List<String> users;
    private boolean setMinTemperature;
    private boolean setMaxTemperature;
    private Map<String,String> cities;
    private Map<String,String> countries;
    private float minTemperature;
    private float maxTemperature;
    private Spinner minTemperatureUI;
    private Spinner maxTemperatureUI;
    private String[] selectedWeatherTypes;
    private String[] invitations;  
    
    @PostConstruct
    public void init() {
        countries  = new PlaceManager().getCountries();
        event = new Event();
        cities = new HashMap<>();

        minTemperature = 20;
        maxTemperature = 30;
        
        ArrayList<String> selectedWeatherTypesList = new ArrayList<>();
        for (WeatherType wt : WeatherType.values()) {
            if (wt.isIsBadWeatherDefault()) {
                selectedWeatherTypesList.add(wt.getName());
            }
        }
        selectedWeatherTypes = new String[0];
        selectedWeatherTypes = selectedWeatherTypesList.toArray(selectedWeatherTypes);
        
    }

    public Map<String, String> getCountries() {
        return countries;
    }

    public Map<String, String> getCities() {
        return cities;
    }

    public void onCountryChange() {
        if (event.getCountry() != null && !event.getCountry().equals("")) {
            cities = placeManager.getCities(event.getCountry());
        } else {
            cities = new HashMap<>();
        }
    }

    public Event getEvent() {
        return event;
    }

    public void setEvent(Event event) {
        this.event = event;
    }

    public boolean isSetMinTemperature() {
        return setMinTemperature;
    }

    public void setSetMinTemperature(boolean setMinTemperature) {
        this.setMinTemperature = setMinTemperature;
    }

    public boolean isSetMaxTemperature() {
        return setMaxTemperature;
    }

    public void setSetMaxTemperature(boolean setMaxTemperature) {
        this.setMaxTemperature = setMaxTemperature;
    }

    public float getMinTemperature() {
        return minTemperature;
    }

    public void setMinTemperature(float minTemperature) {
        this.minTemperature = minTemperature;
    }

    public float getMaxTemperature() {
        return maxTemperature;
    }

    public void setMaxTemperature(float maxTemperature) {
        this.maxTemperature = maxTemperature;
    }
    
    public void changeEnabledMinTemperature() {
        if (setMinTemperature)
            minTemperatureUI.setDisabled(false);
        else
            minTemperatureUI.setDisabled(true);
    }

    public void changeEnabledMaxTemperature() {
        if (setMaxTemperature) {
            maxTemperatureUI.setDisabled(false);
        } else {
            maxTemperatureUI.setDisabled(true);
        }
    }

    public Spinner getMinTemperatureUI() {
        return minTemperatureUI;
    }

    public void setMinTemperatureUI(Spinner minTemperatureUI) {
        this.minTemperatureUI = minTemperatureUI;
    }

    public Spinner getMaxTemperatureUI() {
        return maxTemperatureUI;
    }

    public void setMaxTemperatureUI(Spinner maxTemperatureUI) {
        this.maxTemperatureUI = maxTemperatureUI;
    }
    
    public List<String> getWeatherTypes() {
        return Arrays.asList(WeatherType.getStringWeatherTypes());
    }

    public String[] getSelectedWeatherTypes() {
        return selectedWeatherTypes;
    }

    public void setSelectedWeatherTypes(String[] selectedWeatherTypes) {
        this.selectedWeatherTypes = selectedWeatherTypes;
    }
    
    public String getOutdoorWellFormatted() {
        return event.isOutdoor() ? "Yes" : "No";
    }
    
    public List<String> getUsers() {
        return userManager.getAllUsernamesExceptSelf();
    }
    
    public String[] getInvitations() {
        return invitations;
    }

    public void setInvitations(String[] invitations) {
        this.invitations = invitations;
    }
    
    public String getMinTemperatureString() {
        return setMinTemperature ? String.valueOf(minTemperature) : "Not enabled";
    }
    
    public String getMaxTemperatureString() {
        return setMaxTemperature ? String.valueOf(maxTemperature) : "Not enabled";
    }
    
    public String getBadWeathersWellFormatted() {
        String result = new String();
        for (String s: selectedWeatherTypes) 
            result = result.concat(s).concat(", ");
        result = result.isEmpty() ? "None" : result.substring(0, result.length() - 2);
        return result;
    }
    
    public String create() {
        event.setCreationTimestamp(new Date());
        event.setMinTemperature(setMinTemperature ? minTemperature : null);
        event.setMaxTemperature(setMaxTemperature ? maxTemperature : null);
        event.setCreator(userManager.getLoggedUser());
        event = eventManager.newEvent(event, selectedWeatherTypes);

        invitationManager.sendInvitationsTo(invitations, event);
        
        forecastManager.setForecastOrScheduleItsUpdate(event);
        
        return "/user/userpage?faces-redirect=true";
    }
    
    public void confirmCreation() {
        FacesContext context = FacesContext.getCurrentInstance();
        FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_INFO, "Successful",  "The event has been created");
        context.getExternalContext().getFlash().setKeepMessages(true);
        context.addMessage(null, message);
    }

    public int getMinTemperatureAvaiable() {
        return Event.MIN_TEMPERATURE_AVAIABLE;
    }
    
    public int getMaxTemperatureAvaiable() {
        return Event.MAX_TEMPERATURE_AVAIABLE;
    }
    
    public String getWeatherForecast() {
        WeatherForecast weatherForcast = forecastManager.getForecast(event);
        if (weatherForcast == null) {
            return "A weather forecast is not avaiable for this event yet.";
        }
        return weatherForcast.getWeatherType().getName() + " with an average temperature of " + String.valueOf(weatherForcast.getTemperature()) + " °C.";
    }
    
    public void validateEndDate(FacesContext context, UIComponent component, Object value) throws ValidatorException {
        if (event==null || event.getStartTime() == null)
            return;
        
        if (value ==null)
            return;
        
        Date endDate = (Date)value;
        
        if (endDate.before(event.getStartTime()))
            throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "The end date must be after the start date", "The end date must be after the start date"));
    }
    
    public void validateMaximumTemperature(FacesContext context, UIComponent component, Object value) throws ValidatorException {
        if (!setMinTemperature || !setMaxTemperature)
            return;
        if (value == null)
            return;
        
        if (minTemperature > (float)value)
            throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_ERROR, "The maximum temperature must be greater than the minimum one", "The maximum temperature must be greater than the minimum one"));
    }
  
}
